在 shell 中可以运行程序, 而 shell 本身就是一种编程语言. shell 程序, 一般称之为 shell 脚本.
shell 脚本
shell 脚本是一个包含一系列命令的文件. 运行一个脚本就是运行这个文件中 的每个命令.
脚本中除了命令之外还包括以下元素.
- 变量 脚本中可以定义变量
- 用户输入 read 命令告诉 shell 要从标准输入中读入一个字符串
- 控制 包含 if..then..else..fi 控制语句. 还有其他 while/case和for
- 环境
smsh1 命令行解析
smsh1 由三个文件组成: smsh1.c, splitline.c 和 excute.c
smsh.h
#include <sys/types.h> #define YES 1 #define NO 0 /* next_cmd 从输入流中读入下一个命令. 它调用 malloc 来分配内存以接受 * 任意长度的命令行. 碰到文件结束覆, 它返回 NULL. */ char *next_cmd(); /* splitline 将一个字符串分解为字符串数组, 并返回这个数组. * 它调 malloc 来分配内存以接受任意参数个数的命令行. * 这个数组由 NULL 标记结束. */ char **splitline(char *); void freelist(char **); void *emalloc(size_t); void *erealloc(void *, size_t); /* execute 使用 fork, execvp 和 wait 来运行一个命令. * execute 返回命令的结束状态 */ int execute(char **); void fatal(char *, char *, int);
smsh1.c
/* smsh1.c small - shell version 1 * first really usefull version after prompting shell * this one parses the command line into strings * uses fork, exec, wait, and ignores signals */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include "smsh.h" #define DFL_PROMPT ">" int main() { char *cmdline, *prompt, **arglist; int result; void setup(); prompt = DFL_PROMPT; setup(); while ((cmdline = next_cmd(prompt, stdin)) != NULL){ if ((arglist = splitline(cmdline)) != NULL){ result = execute(arglist); freelist(arglist); } free(cmdline); } return 0; } void setup() { signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); } void fatal(char *s1, char * s2, int n) { fprintf(stderr, "Error: %s, %s\n", s1, s2); exit(n); }
splitline.c
/* splitline.c - command reading and parsing functions for smsh * * char *next_cmd(char *prompt, FILE *fp) - get next command * char **splitline(char *str); - parse a string */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "smsh.h" char *next_cmd(char *prompt, FILE *fp) { char *buf; int bufspace = 0; int pos = 0; int c; printf("%s", prompt); while ((c = getc(fp)) != EOF){ if (pos + 1 >= bufspace){ if (bufspace == 0) buf = emalloc(BUFSIZ); else buf = erealloc(buf, bufspace + BUFSIZ); bufspace += BUFSIZ; } if (c == '\n') break; buf[pos++] = c; } if (c == EOF && pos == 0) return NULL; buf[pos] = '\0'; return buf; } #define is_delim(x) ((x) == ' '||(x) == '\t') char **splitline(char *line) { char *newstr(); char **args; int spots = 0; int bufspace = 0; int argnum = 0; char *cp = line; char *start; int len; if (line = NULL) return NULL; args = emalloc(BUFSIZ); bufspace = BUFSIZ; spots = BUFSIZ/sizeof(char *); while (*cp != '\0') { while (is_delim(*cp)) cp++; if(*cp == '\0') break; if (argnum + 1 >= spots){ args = erealloc(args, bufspace + BUFSIZ); bufspace += BUFSIZ; spots += (BUFSIZ / sizeof(char *)); } start = cp; len = 1; while (*++cp != '\0' && !(is_delim(*cp))) len++; args[argnum++] = newstr(start, len); } args[argnum] = NULL; return args; } char *newstr(char *s, int l) { char *rv = emalloc(l + 1); rv[l] = '\0'; strncpy(rv, s, l); return rv; } void freelist(char **list) { char **cp = list; while (*cp) free(*cp++); free(list); } void *emalloc(size_t n) { void *rv; if ((rv = malloc(n)) == NULL) fatal("out of memory", "", 1); return rv; } void *erealloc(void *p, size_t n) { void *rv; if ((rv = realloc(p, n)) == NULL) fatal("relloc() failed", "", 1); return rv; }
execute.c
/* execute.c - code used by small shell to execute commands */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <sys/wait.h> int execute(char *argv[]) { int pid; int child_info = -1; if (argv[0] == NULL) return 0; if ((pid = fork()) == -1) perror("fork"); else if (pid == 0){ signal(SIGINT, SIG_DFL); signal(SIGQUIT, SIG_DFL); execvp(argv[0], argv); perror("cannot execute command"); exit(1); } else { if (wait(&child_info) == -1) perror("wait"); } return child_info; }
使用下面命令编译:
cc smsh1.c splitline.c execute.c -o smsh1